<template>
  <div>
    <el-card v-loading="loading">
      <!-- 查询表单 -->
      <el-form :inline="true" :model="queryForm" class="mb-[20px]">
        <div class="flex flex-wrap gap-4">
          <el-form-item label="ID" class="!mb-4">
            <el-input
              v-model="queryForm.id"
              placeholder="请输入ID"
              clearable
              class="!w-[200px]"
            />
          </el-form-item>
          <el-form-item label="学号" class="!mb-4">
            <el-input
              v-model="queryForm.number"
              placeholder="请输入学号"
              clearable
              class="!w-[200px]"
            />
          </el-form-item>
          <el-form-item label="姓名" class="!mb-4">
            <el-input
              v-model="queryForm.name"
              placeholder="请输入姓名"
              clearable
              class="!w-[200px]"
            />
          </el-form-item>
        </div>

        <div
          class="flex items-center justify-between w-full mt-4 border-t pt-4"
        >
          <div class="flex gap-2">
            <el-button type="primary" @click="handleQuery">
              <el-icon class="mr-2"><Search /></el-icon>查询
            </el-button>
            <el-button @click="resetForm">
              <el-icon class="mr-2"><Refresh /></el-icon>重置
            </el-button>
          </div>
          <div class="flex gap-2">
            <el-button type="success" @click="handleDownloadTemplate">
              <el-icon class="mr-2"><Download /></el-icon>下载模板
            </el-button>
            <el-button type="warning" @click="handleImport">
              <el-icon class="mr-2"><Upload /></el-icon>导入白名单
            </el-button>
            <el-button type="primary" @click="handleAdd">
              <el-icon class="mr-2"><Plus /></el-icon>新增
            </el-button>
          </div>
        </div>
      </el-form>

      <!-- 表格部分 -->
      <PureTable
        :data="tableData"
        :columns="columns"
        :loading="loading"
        header-align="center"
        align="center"
        border
      />
      <!-- 分页 -->
      <div class="flex justify-end mt-4">
        <el-pagination
          v-model:current-page="pagination.currentPage"
          v-model:page-size="pagination.pageSize"
          :total="pagination.total"
          :page-sizes="[10, 20, 50, 100]"
          layout="total, sizes, prev, pager, next, jumper"
          background
          @size-change="handleSizeChange"
          @current-change="handlePageChange"
        />
      </div>

      <!-- 编辑/新增弹出框 -->
      <el-dialog
        v-model="dialogVisible"
        :title="isEdit ? '编辑白名单' : '新增白名单'"
        width="500px"
        :destroy-on-close="true"
      >
        <el-form
          ref="formRef"
          :model="formData"
          :rules="rules"
          label-width="100px"
          class="py-[20px]"
        >
          <el-form-item label="学号" prop="henau_number">
            <el-input
              v-model="formData.henau_number"
              placeholder="请输入学号"
            />
          </el-form-item>
          <el-form-item label="姓名" prop="name">
            <el-input v-model="formData.name" placeholder="请输入姓名" />
          </el-form-item>
          <el-form-item label="允许IP" prop="allow_ip">
            <el-select
              v-model="formData.allow_ip"
              multiple
              filterable
              allow-create
              placeholder="请输入或选择IP地址"
              class="w-full"
            >
              <el-option label="0.0.0.0" value="0.0.0.0" />
            </el-select>
            <div class="text-gray-400 text-sm mt-1">
              可以输入多个IP地址，0.0.0.0 表示允许所有IP
            </div>
          </el-form-item>
          <el-form-item label="角色组" prop="default_roles">
            <el-select
              v-model="formData.default_roles"
              multiple
              filterable
              placeholder="请选择角色"
              class="w-full"
            >
              <el-option
                v-for="role in roleList"
                :key="role.id"
                :label="role.name"
                :value="role.id"
              />
            </el-select>
          </el-form-item>
        </el-form>
        <template #footer>
          <div class="flex justify-end gap-2">
            <el-button @click="dialogVisible = false">取消</el-button>
            <el-button type="primary" @click="handleSave">保存</el-button>
          </div>
        </template>
      </el-dialog>

      <!-- 导入白名单弹窗 -->
      <el-dialog
        v-model="importDialogVisible"
        title="导入白名单"
        width="500px"
        :destroy-on-close="true"
      >
        <el-upload
          class="upload-demo"
          drag
          :auto-upload="false"
          :show-file-list="true"
          :on-change="handleFileUpload"
          :before-upload="
            file => {
              const isExcel = ['xlsx', 'xls'].includes(
                file.name.split('.').pop().toLowerCase()
              );
              if (!isExcel) {
                ElMessage.error('只能上传 Excel 文件（.xlsx 或 .xls 格式）');
              }
              return isExcel;
            }
          "
          accept=".xlsx,.xls"
        >
          <el-icon class="el-icon--upload"><upload-filled /></el-icon>
          <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
          <template #tip>
            <div class="el-upload__tip text-center">
              只能上传 Excel 文件（.xlsx 或 .xls 格式），且文件大小不能超过 10MB
            </div>
          </template>
        </el-upload>
      </el-dialog>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, h, onMounted } from "vue";
import {
  Search,
  Edit,
  Delete,
  Refresh,
  Plus,
  Download,
  Upload,
  UploadFilled
} from "@element-plus/icons-vue";
import { ElMessage, ElMessageBox, ElButton, ElIcon, ElTag } from "element-plus";
import {
  getAllowByPage,
  addAllow,
  setAllow,
  delAllow,
  preAllow,
  getAllRoles
} from "@/api/index";
import * as XLSX from "xlsx";

interface QueryForm {
  id: number | undefined;
  number: number | undefined;
  name: string;
}

interface AllowRecord {
  id: number;
  henau_number: string;
  allow_ip: string;
  created_at: string;
  name: string | null;
}

interface AddAllowParams {
  number: number;
  name: string;
  allow_ip: string[];
  default_roles: number[];
}

interface SetAllowParams extends AddAllowParams {
  id: number;
}

// 查询表单
const queryForm = reactive<QueryForm>({
  id: undefined,
  number: undefined,
  name: ""
});

// 表格数据
const tableData = ref<AllowRecord[]>([]);
const loading = ref(false);
const pagination = reactive({
  total: 0,
  pageSize: 10,
  currentPage: 1
});

// 表格列配置
const columns = [
  {
    label: "ID",
    prop: "id",
    align: "center",
    width: 100
  },
  {
    label: "学号",
    prop: "henau_number",
    align: "center",
    width: 180
  },
  {
    label: "姓名",
    prop: "name",
    align: "center",
    width: 150
  },
  {
    label: "允许IP_[0.0.0.0]为允许全部ip",
    prop: "allow_ip",
    minWidth: 200,
    align: "center",
    cellRenderer: ({ row }) => {
      try {
        const ips = JSON.parse(row.allow_ip);
        return h(
          "div",
          { class: "flex flex-wrap gap-1 justify-center items-center" },
          ips.map(ip =>
            h(
              ElTag,
              {
                type: ip === "0.0.0.0" ? "danger" : "info",
                effect: "light",
                class: "mx-1"
              },
              { default: () => ip }
            )
          )
        );
      } catch {
        return row.allow_ip;
      }
    }
  },
  {
    label: "预制角色组",
    prop: "default_roles",
    minWidth: 200,
    align: "center",
    cellRenderer: ({ row }) => {
      try {
        const roleIds = JSON.parse(row.default_roles);
        return h(
          "div",
          { class: "flex flex-wrap gap-1 justify-center items-center" },
          roleIds.map((roleId, index) => {
            const role = roleList.value.find(r => r.id === roleId);
            // 根据角色名称或索引选择不同的类型
            const getTagType = (role, index) => {
              if (!role) return "error"; // 找不到角色时使用 error 类型
              if (role.name.includes("默认")) return "info";
              if (role.name.includes("测试")) return "warning";
              if (role.name.includes("管理员")) return "danger";
              // 循环使用这些类型
              const types = ["success", "warning", "danger", "info"];
              return types[index % types.length];
            };
            return h(
              ElTag,
              {
                type: getTagType(role, index),
                effect: "light",
                class: "mx-1"
              },
              { default: () => (role ? role.name : `错误角色(${roleId})`) }
            );
          })
        );
      } catch {
        return "无角色";
      }
    }
  },
  {
    label: "创建时间",
    prop: "created_at",
    width: 180,
    align: "center"
  },
  {
    label: "操作",
    width: 150,
    align: "center",
    fixed: "right",
    cellRenderer: ({ row }) => {
      return h("div", { class: "flex justify-center gap-2" }, [
        h(
          ElButton,
          {
            type: "primary",
            link: true,
            onClick: () => handleEdit(row)
          },
          {
            default: () => [
              h(
                ElIcon,
                { class: "mr-1" },
                {
                  default: () => h(Edit)
                }
              ),
              "编辑"
            ]
          }
        ),
        h(
          ElButton,
          {
            type: "danger",
            link: true,
            onClick: () => handleDelete(row)
          },
          {
            default: () => [
              h(
                ElIcon,
                { class: "mr-1" },
                {
                  default: () => h(Delete)
                }
              ),
              "删除"
            ]
          }
        )
      ]);
    }
  }
];

// 弹出框相关
const dialogVisible = ref(false);
const isEdit = ref(false);
const formRef = ref();
const formData = reactive({
  id: "",
  henau_number: "",
  name: "",
  allow_ip: [],
  default_roles: []
});

// 表单校验规则
const rules = {
  henau_number: [{ required: true, message: "请输入学号", trigger: "blur" }],
  allow_ip: [
    { required: true, message: "请至少输入一个IP地址", trigger: "change" }
  ],
  default_roles: [
    { required: true, message: "请至少选择一个角色", trigger: "change" }
  ]
};

// 获取表格数据
const fetchData = async () => {
  loading.value = true;
  try {
    const params = {
      page: pagination.currentPage,
      size: pagination.pageSize,
      id: queryForm.id || undefined,
      number: queryForm.number || undefined,
      name: queryForm.name || undefined
    };
    const res = await getAllowByPage(params);
    if (res.status === "success" && res.data) {
      tableData.value = res.data.records;
      pagination.total = res.data.pagination.total;
      pagination.currentPage = res.data.pagination.current_page;
      pagination.pageSize = res.data.pagination.per_page;
    }
  } catch (error) {
    console.error("获取数据失败:", error);
    ElMessage.error("获取数据失败");
  } finally {
    loading.value = false;
  }
};

// 查询
const handleQuery = () => {
  pagination.currentPage = 1;
  fetchData();
};

// 重置表单
const resetForm = () => {
  queryForm.id = undefined;
  queryForm.number = undefined;
  queryForm.name = "";
  handleQuery();
};

// 页码改变
const handlePageChange = (page: number) => {
  pagination.currentPage = page;
  fetchData();
};

// 每页条数改变
const handleSizeChange = (size: number) => {
  pagination.pageSize = size;
  pagination.currentPage = 1;
  fetchData();
};

// 新增
const handleAdd = () => {
  isEdit.value = false;
  formData.id = "";
  formData.henau_number = "";
  formData.name = "";
  formData.allow_ip = ["0.0.0.0"];
  formData.default_roles = [];
  fetchRoleList(); // 获取最新的角色列表
  dialogVisible.value = true;
};

// 编辑
const handleEdit = row => {
  isEdit.value = true;
  formData.id = row.id;
  formData.henau_number = String(row.henau_number);
  formData.name = row.name;
  try {
    formData.allow_ip = JSON.parse(row.allow_ip);
    formData.default_roles = JSON.parse(row.default_roles || "[]");
  } catch {
    formData.allow_ip = ["0.0.0.0"];
    formData.default_roles = [];
  }
  fetchRoleList(); // 获取最新的角色列表
  dialogVisible.value = true;
};

// 删除
const handleDelete = row => {
  ElMessageBox.confirm(
    `确认删除学号为 ${row.henau_number} 的白名单记录吗？`,
    "提示",
    {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      type: "warning"
    }
  )
    .then(async () => {
      try {
        const res = await delAllow({ id: row.id });
        if (res.status === "success") {
          ElMessage.success("删除成功");
          fetchData();
        } else {
          ElMessage.error(res.message || "删除失败");
        }
      } catch (error) {
        console.error("删除失败:", error);
        ElMessage.error("删除失败");
      }
    })
    .catch(() => {});
};

// 保存
const handleSave = () => {
  formRef.value?.validate(async valid => {
    if (valid) {
      try {
        const params = {
          number: Number(formData.henau_number),
          name: formData.name,
          allow_ip: formData.allow_ip,
          default_roles: formData.default_roles || []
        };

        let res;
        if (isEdit.value) {
          res = await setAllow({
            ...params,
            id: Number(formData.id)
          });
        } else {
          res = await addAllow(params);
        }

        if (res.status === "success") {
          ElMessage.success(isEdit.value ? "修改成功" : "添加成功");
          dialogVisible.value = false;
          fetchData();
        } else {
          ElMessage.error(
            res.message || (isEdit.value ? "修改失败" : "添加失败")
          );
        }
      } catch (error) {
        console.error("保存失败:", error);
        ElMessage.error("保存失败");
      }
    }
  });
};

// 导入相关
const importDialogVisible = ref(false);
const headers = {
  Authorization: `Bearer ${localStorage.getItem("token")}`
};

// 角色列表
const roleList = ref([]);

// 获取角色列表
const fetchRoleList = async () => {
  try {
    const res = await getAllRoles();
    if (res.status === "success") {
      roleList.value = res.data;
    }
  } catch (error) {
    console.error("获取角色列表失败:", error);
  }
};

// 下载模板
const handleDownloadTemplate = () => {
  try {
    // 定义表头
    const headers = ["学工号", "限制IP登录", "姓名", "默认角色组"];

    // 创建示例数据
    const exampleData = [
      ["2890322345", "0.0.0.0", "白名单人员", "默认(编辑时删除)"]
    ];

    // 创建工作簿和工作表
    const wb = XLSX.utils.book_new();
    const ws = XLSX.utils.aoa_to_sheet([headers, ...exampleData]);

    // 设置列宽
    const colWidth = headers.map(() => ({ wch: 20 }));
    ws["!cols"] = colWidth;

    // 将工作表添加到工作簿
    XLSX.utils.book_append_sheet(wb, ws, "白名单模板");

    // 生成文件并下载
    XLSX.writeFile(wb, "白名单导入模板.xlsx");
  } catch (error) {
    console.error("生成模板失败:", error);
    ElMessage.error("生成模板失败，请稍后重试");
  }
};

// 打开导入对话框
const handleImport = () => {
  fetchRoleList(); // 获取最新的角色列表
  importDialogVisible.value = true;
};

// 处理文件上传
const handleFileUpload = async file => {
  try {
    // 验证文件类型
    const fileType = file.name.split(".").pop().toLowerCase();
    if (!["xlsx", "xls"].includes(fileType)) {
      ElMessage.error("只能上传 Excel 文件（.xlsx 或 .xls 格式）");
      return false;
    }

    // 验证文件大小（限制为10MB）
    const maxSize = 10 * 1024 * 1024; // 10MB
    if (file.size > maxSize) {
      ElMessage.error("文件大小不能超过 10MB");
      return false;
    }

    const reader = new FileReader();
    reader.onload = async e => {
      const data = new Uint8Array(e.target.result);
      const workbook = XLSX.read(data, { type: "array" });
      const worksheet = workbook.Sheets[workbook.SheetNames[0]];
      const jsonData = XLSX.utils.sheet_to_json(worksheet, {
        header: ["学工号", "限制IP登录", "姓名", "默认角色组"]
      });

      // 移除表头
      jsonData.shift();

      // 验证数据
      const errors = [];
      const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
      const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
      const containsEnglishOrNumber = /[a-zA-Z0-9]/;

      // 确保已获取最新的角色列表
      await fetchRoleList();

      jsonData.forEach((row, index) => {
        const rowNum = index + 2; // Excel行号(加2是因为有表头和0基索引)

        // 检查是否所有字段都存在且不为空
        if (!row["学工号"]) {
          errors.push(`第${rowNum}行：学工号不能为空`);
        }
        if (!row["限制IP登录"]) {
          errors.push(`第${rowNum}行：限制IP登录不能为空`);
        }
        if (!row["姓名"]) {
          errors.push(`第${rowNum}行：姓名不能为空`);
        }
        if (!row["默认角色组"]) {
          errors.push(`第${rowNum}行：默认角色组不能为空`);
        }

        // 验证IP地址格式
        const ips = (row["限制IP登录"] || "").split(",").map(ip => ip.trim());
        ips.forEach(ip => {
          if (ip !== "0.0.0.0" && !ipv4Regex.test(ip) && !ipv6Regex.test(ip)) {
            errors.push(
              `第${rowNum}行：IP地址 ${ip} 格式不正确，必须是有效的IPv4或IPv6地址`
            );
          }
        });

        // 验证默认角色组不包含英文或数字，并且角色必须存在于系统中
        const roleNames = (row["默认角色组"] || "").split(",");
        roleNames.forEach(roleName => {
          const trimmedRoleName = roleName.trim();
          if (containsEnglishOrNumber.test(trimmedRoleName)) {
            errors.push(
              `第${rowNum}行：角色组 ${trimmedRoleName} 不能包含英文或数字`
            );
          }
          // 验证角色是否存在于系统中
          const roleExists = roleList.value.some(
            role => role.name === trimmedRoleName
          );
          if (!roleExists) {
            errors.push(
              `第${rowNum}行：角色组 ${trimmedRoleName} 在系统中不存在，请先在角色管理中添加该角色`
            );
          }
        });
      });

      // 如果有错误，显示错误信息并终止导入
      if (errors.length > 0) {
        ElMessage.error({
          message: h("div", {}, [
            h(
              "div",
              { style: "font-weight: bold; margin-bottom: 10px" },
              "导入失败，请检查以下错误："
            ),
            h(
              "div",
              { style: "max-height: 300px; overflow-y: auto" },
              errors.map(error => h("div", { style: "margin: 5px 0" }, error))
            )
          ]),
          duration: 10000
        });
        return false;
      }

      // 处理数据
      const processedData = {
        list: jsonData.map(row => {
          // 处理角色
          const roleNames = row["默认角色组"].split(",");
          const roleIds = roleNames
            .map(name => {
              const role = roleList.value.find(r => r.name === name.trim());
              return role ? role.id : null;
            })
            .filter(id => id !== null);

          // 处理 IP
          const ipList = row["限制IP登录"].split(",").map(ip => ip.trim());

          return {
            number: parseInt(row["学工号"]),
            allow_ip: ipList,
            name: row["姓名"],
            default_roles: roleIds
          };
        })
      };

      // 调用上传接口
      try {
        const res = await preAllow(processedData);
        if (res.status === "success") {
          ElMessage.success("导入成功");
          importDialogVisible.value = false;
          fetchData();
        } else {
          ElMessage.error(res.message || "导入失败");
        }
      } catch (error) {
        console.error("导入失败:", error);
        ElMessage.error("导入失败，请检查数据格式是否正确");
      }
    };
    reader.readAsArrayBuffer(file.raw);
    return false; // 阻止默认上传
  } catch (error) {
    console.error("文件处理失败:", error);
    ElMessage.error("文件处理失败，请检查文件格式");
    return false;
  }
};

// 导入成功
const handleImportSuccess = response => {
  if (response.status === "success") {
    ElMessage.success("导入成功");
    importDialogVisible.value = false;
    fetchData();
  } else {
    ElMessage.error(response.message || "导入失败");
  }
};

// 导入失败
const handleImportError = () => {
  ElMessage.error("导入失败，请检查文件格式或网络连接");
};

onMounted(() => {
  fetchData();
  fetchRoleList();
});
</script>

<style lang="scss" scoped>
:deep(.el-dialog__body) {
  padding: 0 20px;
}

:deep(.el-table) {
  // 表格基础样式
  .cell {
    padding: 8px 0;
    line-height: 1.5;
  }

  // 表头样式
  .el-table__header {
    th {
      height: 50px;
      font-weight: bold;
      color: var(--el-text-color-primary);
      background-color: var(--el-fill-color-light);
    }
  }

  // 表格行样式
  .el-table__row {
    &:hover {
      background-color: var(--el-fill-color-lighter) !important;
    }

    td {
      padding: 12px 0;
      border-bottom: 1px solid var(--el-border-color-lighter);
    }
  }
}
</style>
